package me.pplay.playtalk.protocol;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import me.pplay.playtalk.data.Globals;
import me.pplay.playtalk.protocol.bean.RspData;
import me.pplay.playtalk.protocol.bean.SendNode;
import me.pplay.playtalk.protocol.bean.TpFileData;
import me.pplay.playtalk.protocol.bean.TpPacket;
import me.pplay.playtalk.util.LogManager;
import me.pplay.playtalk.util.PlayTalkUtil;
import me.pplay.playtalk.util.UserInfo;
import android.util.Log;

public class TpFile extends ProtocolPacket {

	public static final int FILE_TRANS_TYPE_NORMAL = 1;//普通点对点文件
	public static final int FILE_TRANS_TYPE_PHOTO=2;//个人图片
	public static final int FILE_TRANS_TYPE_GROUP=3;//群文件
	public static final int FILE_TRANS_TYPE_AVATAR=4;//头像
	public static final int FILE_TRANS_TYPE_PBK=5;//电话本
	public static final int FILE_TRANS_TYPE_STICKER=9;//sticker
	
	public static final int FILE_LOCAL_ERR_SPACE_FULL = 10;// 手机磁盘空间满
	public static final int FILE_SERVER_TOKEN_OK = 11;// token验证成功
	public static final int FILE_SERVER_TOKEN_INVALID = 12;// token非法
	public static final int FILE_SERVER_UP_REQUEST_OK = 13;// 准许文件上传请求
	public static final int FILE_SERVER_UP_REQUEST_ERR = 14;// 服务器拒绝文件上传请求
	public static final int FILE_SERVER_UP_PROGRESS = 15;// 文件上传进度
	public static final int FILE_SERVER_DOWN_ERR = 16;// 服务器拒绝文件上传请求
	public static final int FILE_SERVER_DOWN_PROGRESS = 17;// 文件上传进度
	public static final int FILE_NET_ERR = 18;// 网络错误
	public static final int FILE_UNKOWN_ERR = 19; // 未知错误
	public static final int FILE_IO_ERR = 20; // 未知错误
	


	private int token = 0;
	private int skyid=0;
	private int fileSize=0;
	private TpFileData filedata;
	private DataCallBack datacallback;
	private boolean isRun = false;
	@Override
	public void tp_recvcb(int result, TpPacket pkt, SendNode node) {
		Log.v("TpFile", "tp_recvcb resulut = " + result);
		switch (result) {
		case ProtocolType.TP_ERRCODE_ERR_SERVER:
		case ProtocolType.TP_ERRCODE_ERR_TPVERSION:
			// case TP_ERRCODE_ERR_SOCKETCLOSE:
		case ProtocolType.TP_ERRCODE_ERR_SOCKETDATAERR:
		case ProtocolType.TP_ERRCODE_ERR_SOCKET:
		case ProtocolType.TP_ERRCODE_ERR_SOCKETRECV:
		case ProtocolType.TP_ERRCODE_ERR_SOCKETSEND:
		case ProtocolType.TP_ERRCODE_ERR_SOCKETCONNECT:
			 Callback(FILE_NET_ERR, null, null);
			break;
		case ProtocolType.TP_ERRCODE_OK: {
			file_packet_process(pkt);
		}
			break;
		}
	}

	@Override
	public void tp_keeplive() {
		// TODO Auto-generated method stub

	}

	@Override
	public boolean tp_sendcb(int cmd, SendNode nodedata) {
		if(0 == this.token && ProtocolType.TLV.TP_TLV_CMD_FILE_TOKEN != nodedata.getCmd())
			return false;
		return tp_send_socket(nodedata.getData());
	}

	public TpFile() {

		ProtocolList sendlist = new ProtocolList();
		setProtocolPacketSendList(sendlist);
		SET_TP_FLAG(TP_FILE_TLV);
		setNeed_bytes((short)8);
	}

	public void tp_file_upload_stop() {
		LogManager.LogShow("TpFile", "tp_file_upload_stop = " + this.isRun);
		if (this.isRun)
			tp_data_stop();
	}
	public void tp_file_upload(String url, String token, int skyid,
			TpFileData filedata,DataCallBack datacallback) {
		String ip = new String(url);
		String[] iparray;
		iparray = ip.split(":");
		this.tp_data_starturl(iparray[0], Integer.parseInt(iparray[1]));
//		this.tp_data_starturl(url, port);
		tp_file_token(skyid, token);
		this.skyid = skyid;//my skyid;
		this.filedata = filedata;
		this.datacallback = datacallback;
		this.isRun = true;
	}
	
	public void tp_file_upload(String url, int port, String token, int skyid,
			TpFileData filedata,DataCallBack datacallback) {
		this.tp_data_starturl(url, port);
		tp_file_token(skyid, token);
		this.skyid = skyid;//my skyid;
		this.filedata = filedata;
		this.datacallback = datacallback;
		this.isRun = true;
		
	}
	public void tp_file_upload(String filename,int filetype,int distSkyid,int gid,String fileDescribe,DataCallBack datacallback) {
		TpFileData filedata = new TpFileData();
		filedata.setSkyID(distSkyid);
		filedata.setGroupID(gid);
		filedata.setFileDescribe(fileDescribe);
		filedata.setFileType((byte)filetype);
		filedata.setFilePathLocal(filename);
		File fd = new File(filename);
		FileInputStream in = null;
		int fileSize=0;
		try {
			in = new FileInputStream(fd);
			fileSize = in.available();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			tp_file_upload_stop();
			datacallback.Callback(FILE_IO_ERR, null, null);
			return;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			tp_file_upload_stop();
			datacallback.Callback(FILE_IO_ERR, null, null);
			return;
		}
		filedata.setFileSize(fileSize);
		tp_file_upload(Globals.FileIpString,Globals.token,Globals.skyid,filedata,datacallback);
	}
	public void tp_file_upload(String filename,int filetype,int distSkyid,int gid,DataCallBack datacallback) {
		tp_file_upload(filename,filetype,distSkyid,gid,"",datacallback);
	}
	private void Callback(int result, RspData resultdata, Object obj) {
		if(FILE_SERVER_TOKEN_OK == result){
			tp_file_uploadreq(this.skyid, this.filedata);
		}else if(FILE_SERVER_UP_REQUEST_OK == result){
			TpFileData newFiledata= (TpFileData)obj;//need to make sure 
			this.fileSize = newFiledata.getFileSize();
			LogManager.LogShow("TpFile", "start getFileOffset" + newFiledata.getFileOffset()
					+"getFileSize" + newFiledata.getFileSize());
			if(!tp_file_upload(this.skyid, newFiledata)){
				tp_file_upload_stop();
				datacallback.Callback(FILE_IO_ERR, resultdata, obj);
				return;
			}
		}else if(FILE_SERVER_UP_PROGRESS == result){
			TpFileData newFiledata= (TpFileData)obj;//need to make sure 
			newFiledata.setFileSize(this.fileSize);
			LogManager.LogShow("TpFile", "continue getFileOffset" + newFiledata.getFileOffset()
					+"getFileSize" + newFiledata.getFileSize());
			if(newFiledata.getFileOffset()< newFiledata.getFileSize()){
				if(!tp_file_upload(this.skyid, newFiledata)){
					tp_file_upload_stop();
					datacallback.Callback(FILE_IO_ERR, resultdata, obj);
					return;
				}
			}else{
				tp_file_upload_stop();
			}
			datacallback.Callback(result, resultdata, obj);  
				
		}else{
			tp_file_upload_stop();
			datacallback.Callback(result, resultdata, null);
		}
	}

	private void file_packet_process(TpPacket pkt) {
		byte[] data = pkt.getUploadData();
		int pos = 0;
		RspData rspdata = new RspData();
		int cmd;
		int len;
		cmd = PlayTalkUtil.ReadDWordValue(data, pos);
		pos += 4;
		len = PlayTalkUtil.ReadDWordValue(data, pos);
		pos += 4;
		switch (cmd) {
		case ProtocolType.TLV.TP_TLV_CMD_FILE_TOKEN_RESP: {
			int result = 0;
			result = tp_file_token_resp(data, pos, len);
			if (0 == result)
				token = 1;
			Callback(0 == result?FILE_SERVER_TOKEN_OK:FILE_SERVER_TOKEN_INVALID, rspdata,null);
		}
			break;
		case ProtocolType.TLV.TP_TLV_CMD_FILE_UPLOAD_REQ_RESP:/** < . */
		{
			TpFileData pFile = tp_file_upload_request_resp(data, pos, len);
			// 通知应用
			if(pFile!=null &&pFile.getFileOffset() == pFile.getFileSize()
					&&pFile.getFileOffset()>0){
				this.fileSize = pFile.getFileSize();
				Callback(FILE_SERVER_UP_PROGRESS,rspdata, pFile);
			}
			else
				Callback(null != pFile?FILE_SERVER_UP_REQUEST_OK:FILE_SERVER_UP_REQUEST_ERR, rspdata,pFile);
		}
			break; 
		case ProtocolType.TLV.TP_TLV_CMD_FILE_UPLOAD_RESP:/** < . */
		{

			TpFileData pFile = tp_file_upload_resp(data, pos, len);
			// 通知应用 
			Callback(FILE_SERVER_UP_PROGRESS,rspdata, pFile);
		}
			break;
		// case ProtocolType.TLV.TP_TLV_CMD_FILE_DOWNLOAD_RESP:/**< . */
		// {
		// FILE_TRANS_S* pFile = NULL;
		// DWORD result = 0;
		// result = tp_file_download_real_resp((uint8 *)data, len, &pFile);
		// //通知应用
		// if(FILE_LOCAL_ERR_SPACE_FULL == result)
		// FILE_CB_EVENT(p_file,FILE_LOCAL_ERR_SPACE_FULL, pFile,
		// &rspdata->common_data);
		// else
		// FILE_CB_EVENT(p_file,FILE_SERVER_DOWN_PROGRESS, pFile,
		// &rspdata->common_data);
		//
		// im_fileTransDestroy(pFile, TRUE);
		// }
		// break;
		default:
			// FILE_CB_EVENT(p_file, FILE_UNKOWN_ERR,&rspdata->common_data,0);
			break;
		}
	}

	private void tp_file_token(int skyid, String token) {
		int pos = 0;
		byte[] p = new byte[2048];
		int nPackageLen = 0;

		Log.v("TpFile", "tp_file_cmd_auth()" + token);

		// Total Type
		pos += PlayTalkUtil.WriteValue(p, pos, ProtocolType.TLV.TP_TLV_CMD_FILE_TOKEN);
		// Total Lenth
		pos += PlayTalkUtil.WriteValue(p, pos, (int) 0);

		// token
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_TOKEN,
				token.getBytes());

		// skyID
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_SKYID, skyid);

		nPackageLen = pos;
		pos = PlayTalkUtil.TLV_TYPE_LEN;
		pos += PlayTalkUtil.WriteValue(p, pos, nPackageLen - PlayTalkUtil.TLV_HEADER_LEN);

		byte[] p_real = new byte[nPackageLen];
		System.arraycopy(p, 0, p_real, 0, nPackageLen);
		tp_file_senddata_cmn(ProtocolType.TLV.TP_TLV_CMD_FILE_TOKEN, 0, p_real,
				true, null);
	}

	private int tp_file_token_resp(byte[] data, int offset, int nDataLen) {
		int pos = offset;
		int result = 0;
		int t = 0;
		int l = 0;
		do {
			t = PlayTalkUtil.ReadDWordValue(data, pos);
			pos += 4;
			l = PlayTalkUtil.ReadDWordValue(data, pos);
			pos += 4;
			if (t == ProtocolType.TLV.TLV_CODE_RESULT) {
				result = PlayTalkUtil.ReadWordValue(data, pos);
				return result;
			}
			pos += l;
		} while (pos - offset < nDataLen);

		return result;
	}

	private void tp_file_uploadreq(int skyid, TpFileData pFile) {

		int pos = 0;
		byte[] p = new byte[2048];
		if (0 == pFile.getFileSize()) {
			return;
		}
		Log.v("TpFile", "tp_file_upload_request()");

		// Total Type
		pos += PlayTalkUtil.WriteValue(p, pos, ProtocolType.TLV.TP_TLV_CMD_FILE_UPLOAD_REQ);
		// Total Lenth
		pos += PlayTalkUtil.WriteValue(p, pos, (int) 0);

		// local file path
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_FILENAME, pFile
				.getFilePathLocal().getBytes());

		// file size
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_FILESIZE,
				pFile.getFileSize());

		// file type
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_TYPE,
				pFile.getFileType());

		// imsi
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_IMSI, UserInfo
				.getImsi().getBytes());

		// skyID
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_SKYID, skyid);

		// group ID
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_GROUPID,
				pFile.getGroupID());

		// dist skyID
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_DISTSKYID,
				pFile.getSkyID());

		// file description
		{
			// BYTE* pTmp = p;
			int pTmp = pos;
			int len = 0;

			pos += PlayTalkUtil.WriteValue(p, pos, ProtocolType.TLV.TLV_CODE_FILE_REMARK);
			pos += PlayTalkUtil.WriteValue(p, pos, len);

			pos += PlayTalkUtil.WriteValue(p, pos, new String("remark").getBytes());
			p[pos++] = (byte) 0xc0;
			p[pos++] = (byte) 0x80;
			pos += PlayTalkUtil.WriteValue(p, pos, pFile.getFileDescribe().getBytes());
			p[pos++] = (byte) 0xc0;
			p[pos++] = (byte) 0x80;
			pos += PlayTalkUtil.WriteValue(p, pos, new String("filter").getBytes());
			p[pos++] = (byte) 0xc0;
			p[pos++] = (byte) 0x80;
			pos += PlayTalkUtil.WriteValue(p, pos, pFile.getFileFilter().getBytes());
			p[pos++] = (byte) 0xc0;
			p[pos++] = (byte) 0x80;

			len = pos - pTmp - PlayTalkUtil.TLV_HEADER_LEN;
			pos = pTmp + PlayTalkUtil.TLV_TYPE_LEN;
			pos += PlayTalkUtil.WriteValue(p, pos, len);
			pos += len;
		}

		int nPackageLen = pos;
		pos = PlayTalkUtil.TLV_TYPE_LEN;
		pos += PlayTalkUtil.WriteValue(p, pos, nPackageLen - PlayTalkUtil.TLV_HEADER_LEN);

		byte[] p_real = new byte[nPackageLen];
		System.arraycopy(p, 0, p_real, 0, nPackageLen);
		tp_file_senddata_cmn(ProtocolType.TLV.TP_TLV_CMD_FILE_UPLOAD_REQ, 0,
				p_real, true, null);
	}

	private TpFileData tp_file_upload_request_resp(byte[] data, int offset,
			int nDataLen) {
		int pos = offset;
		int result = 0;
		int t = 0;
		int l = 0;
		TpFileData pFile = new TpFileData();
		Log.v("TpFile","tp_file_upload_request_resp()");
		do {
			t = PlayTalkUtil.ReadDWordValue(data, pos);
			pos += 4;
			l = PlayTalkUtil.ReadDWordValue(data, pos);
			pos += 4;

			switch (t) {
			case ProtocolType.TLV.TLV_CODE_FILENAME: {
				byte[] dst = new byte[l];
				System.arraycopy(data, pos, dst, 0, l);
				String filePathLocal = new String(dst);
				pFile.setFilePathLocal(filePathLocal);
			}
				break;
			case ProtocolType.TLV.TLV_CODE_FILESIZE:
				pFile.setFileSize(PlayTalkUtil.ReadDWordValue(data, pos));
				break;
			case ProtocolType.TLV.TLV_CODE_OFFSET:
				pFile.setFileOffset(PlayTalkUtil.ReadDWordValue(data, pos));
				break;
			case ProtocolType.TLV.TLV_CODE_TYPE:
				pFile.setFileType(PlayTalkUtil.ReadByteValue(data, pos));
				break;
			case ProtocolType.TLV.TLV_CODE_SKYID:
				PlayTalkUtil.ReadDWordValue(data, pos);
				break;
			case ProtocolType.TLV.TLV_CODE_GROUPID:
				pFile.setGroupID(PlayTalkUtil.ReadDWordValue(data, pos));
				break;
			case ProtocolType.TLV.TLV_CODE_FILEPATH: {
				byte[] dst = new byte[l];
				System.arraycopy(data, pos, dst, 0, l);
				String filePathServer = new String(dst);
				pFile.setFilePathServer(filePathServer);
			}
				break;
			case ProtocolType.TLV.TLV_CODE_SERVERID:
				pFile.setServerID(PlayTalkUtil.ReadDWordValue(data, pos));
				break;
			case ProtocolType.TLV.TLV_CODE_DISTSKYID:
				pFile.setSkyID(PlayTalkUtil.ReadDWordValue(data, pos));
				break;
			case ProtocolType.TLV.TLV_CODE_RESULT:
				result = PlayTalkUtil.ReadWordValue(data, pos);
				if (result != 0)
					return null;
				break;
			}
			pos += l;
		} while (pos - offset < nDataLen);
		return pFile;
	}

	private boolean tp_file_upload(int skyid, TpFileData pFile) {

		
		int pos = 0;
		byte[] p = new byte[1024*5];
		if(pFile.getFileSize() == pFile.getFileOffset())
			return false;
		File fd = new File(pFile.getFilePathLocal());
		FileInputStream in = null;
		try {
			in = new FileInputStream(fd);
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
			return false;
		}
		
		Log.v("TpFile","tp_file_upload_real()");

		//Total Type
		pos += PlayTalkUtil.WriteValue(p, pos, ProtocolType.TLV.TP_TLV_CMD_FILE_UPLOAD);
		//Total Lenth
		pos += PlayTalkUtil.WriteValue(p, pos,(int)0);
		
		//file offset
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_OFFSET, pFile.getFileOffset());

		//group ID
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_GROUPID, pFile.getGroupID());

		//file type
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_TYPE, pFile.getFileType());

		//skyID
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_SKYID, skyid);

		//file path on server
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_FILEPATH, pFile.getFilePathServer().getBytes());

		//file path local
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_FILENAME, pFile.getFilePathLocal().getBytes());

		//file size
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_FILESIZE, pFile.getFileSize());

		//server id
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_SERVERID, pFile.getServerID());

		//dist skyID
		pos += PlayTalkUtil.TLV_Encode(p, pos, ProtocolType.TLV.TLV_CODE_DISTSKYID, pFile.getSkyID());

		//file contenet
		{
			int len = 0;

			//Type
			pos += PlayTalkUtil.WriteValue(p, pos,  ProtocolType.TLV.TLV_CODE_CONTENT);
			//Total Lenth
			pos += PlayTalkUtil.WriteValue(p, pos, (int) 0);
			
			try{
				in.skip(pFile.getFileOffset());
				len = in.read(p,pos,1024*3);
				in.close();
			}catch (IOException e) {
				e.printStackTrace(); 
				Log.v("ProtocolPacket", "IOException resulut = " );
				return false;
			}
			

			//Total Lenth
			pos -= PlayTalkUtil.TLV_LEN_LEN;
			pos += PlayTalkUtil.WriteValue(p, pos, (int)len);
			pos += len;
		}

		int nPackageLen = pos;
		pos = PlayTalkUtil.TLV_TYPE_LEN;
		pos += PlayTalkUtil.WriteValue(p, pos, nPackageLen - PlayTalkUtil.TLV_HEADER_LEN);
 
		byte[] p_real = new byte[nPackageLen];
		System.arraycopy(p, 0, p_real, 0, nPackageLen); 

//		{
//			File fdd = new File(pFile.getFilePathLocal()+".bak");
//			FileInputStream inn = null;
//			try {
//				inn = new FileInputStream(fd);
//				inn.
//			} catch (FileNotFoundException e1) {
//				// TODO Auto-generated catch block
//				e1.printStackTrace();
//				return false;
//			}
//		}
		tp_file_senddata_cmn(ProtocolType.TLV.TP_TLV_CMD_FILE_UPLOAD, 0, p_real,true, null);
		return true;
	}

	private TpFileData tp_file_upload_resp(byte[] data, int offset, int nDataLen) {
		int pos = offset;
		int result = 0;
		int t = 0;
		int l = 0;
		TpFileData pFile = new TpFileData();
		Log.v("TpFile","tp_file_upload_resp()");
		do {
			t = PlayTalkUtil.ReadDWordValue(data, pos);
			pos += 4;
			l = PlayTalkUtil.ReadDWordValue(data, pos);
			pos += 4;
			switch (t) {
			case ProtocolType.TLV.TLV_CODE_OFFSET:
				pFile.setFileOffset(PlayTalkUtil.ReadDWordValue(data, pos));
				break;
			case ProtocolType.TLV.TLV_CODE_SKYID:
				PlayTalkUtil.ReadDWordValue(data, pos);
				break;
			case ProtocolType.TLV.TLV_CODE_GROUPID:
				pFile.setGroupID(PlayTalkUtil.ReadDWordValue(data, pos));
				break;
			case ProtocolType.TLV.TLV_CODE_TYPE:
				pFile.setFileType(PlayTalkUtil.ReadByteValue(data, pos));
				break;
			case ProtocolType.TLV.TLV_CODE_FILENAME: {
				byte[] dst = new byte[l];
				System.arraycopy(data, pos, dst, 0, l);
				String filePathLocal = new String(dst);
				pFile.setFilePathLocal(filePathLocal);
			}
				break;
			case ProtocolType.TLV.TLV_CODE_FILEPATH: {
				byte[] dst = new byte[l];
				System.arraycopy(data, pos, dst, 0, l);
				String filePathServer = new String(dst);
				pFile.setFilePathServer(filePathServer);
			}
				break;
			case ProtocolType.TLV.TLV_CODE_SERVERID:
				pFile.setServerID(PlayTalkUtil.ReadDWordValue(data, pos));
				break;
			case ProtocolType.TLV.TLV_CODE_DISTSKYID:
				pFile.setSkyID(PlayTalkUtil.ReadDWordValue(data, pos));
				break;
			case ProtocolType.TLV.TLV_CODE_RESULT:
				result = PlayTalkUtil.ReadWordValue(data, pos);
//				if (result == 0)
//					return null;
				break;
			}
			pos += l;
		} while (pos - offset < nDataLen);
		return pFile;
	}

	private void tp_file_senddata_cmn(int cmd, int timeout, byte[] data,
			boolean isappend, DataCallBack callBack) {
		ProtocolList list = getProtocolPacketSendList();
		if (isappend)
			list.tp_data_append_send(cmd, timeout, data, callBack);
		else
			list.tp_data_prepend_send(cmd, timeout, data, callBack);
	}


}
